#include <stdio.h>
#include <string.h>
#include <iconv.h>

/*
 * APIs:
 * iconv_t iconv_open(const char *tocode, const char *fromcode);
 * size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
 * int iconv_close(iconv_t cd);
 * iconv_open函数用来打开一个编码转换的流，
 * iconv函数的作用是实际进行转换，
 * iconv_close函数的作用就是关闭这个流
 *
 * 常值得注意的地方是：iconv函数会修改参数in和参数out指针所指向的地方，
 * 也就是说，在调用iconv函数之前，我们的in和inbuf指针以及 out和outbuf指针指向的是同一块内存区域，
 * 但是调用之后out指针所指向的地方就不是outbuf了，同理in指针。所以要
 * char *in = inbuf;
 * char *out = outbuf;
 * 另存一下，使用或者释放内存的时候也要使用原先的那个指针outbuf和inbuf
 *
 *
 * 下面是一个测试例子:
 * UTF8 -> GB2312
 * GB2312 -> UTF8
 */
int main(int argc, char *argv[]) {
  char inbuf[100] = "这是测试数据";
  char *pin = inbuf;
  size_t inleft = strlen(pin) + 1;

  char outbuf_gb2312[100];
  char *pout_gb2312 = outbuf_gb2312;
  size_t outleft_gb2312 = 100;

  char outbuf_utf8[100];
  char *pout_utf8 = outbuf_utf8;
  size_t outleft_utf8 = 100;

  // 打开的时候源在后, 目标在前

  // UTF8 -> GB2312
  iconv_t cd = iconv_open("GB2312", "UTF8");
  if((int) cd == -1)
    return -1;
  if((int)iconv(cd, &pin, &inleft, &pout_gb2312, &outleft_gb2312) == -1)
    return -1;
  iconv_close(cd);

  // GB2312 -> UTF8
  // 注意: 在调用iconv之后, pout_gb2312已经被修改, 所以需要reset.
  pout_gb2312 = outbuf_gb2312;
  outleft_gb2312 = strlen(pout_gb2312) + 1;
  printf("%d\n", outleft_gb2312);

  cd = iconv_open("UTF8", "GB2312");
  if((int) cd == -1)
    return -1;
  if((int)iconv(cd, &pout_gb2312, &outleft_gb2312, &pout_utf8, &outleft_utf8) == -1)
    return -1;
  iconv_close(cd);

  printf("UTF8: %s\n", inbuf);
  printf("GB2312: %s\n", outbuf_gb2312);
  printf("UTF8: %s\n", outbuf_utf8);
  return 0;
}
